// 树上操作
// https://soj.turingedu.cn/problem/61300/
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
const int inf = 0x3f3f3f3f;
#define rf(i, n) for (int i = 1; i <= (n); ++i)
const int max_size = 5 + 100;
const int maxn = 5 + 2e5;

struct Segtree {
    ll val[maxn << 2], tag[maxn << 2];
    inline void maintain(int u) { val[u] = val[u << 1] + val[u << 1 | 1]; }
    inline void update_node(int u, int l, int r, int x) { val[u] += (r - l + 1) * x, tag[u] += x; }
    inline void pushdown(int u, int l, int r) {
        if (tag[u] == 0) return;
        int mid = l + r >> 1;
        update_node(u << 1, l, mid, tag[u]);
        update_node(u << 1 | 1, mid + 1, r, tag[u]);
    }

    void update(int u, int l, int r, int s, int t, int x) {
        if (s <= l && r <= t) {
            update_node(u, l, r, x);
            return;
        }
        int mid = l + r >> 1;
        if (s <= mid) update(u << 1, l, mid, s, t, x);
        if (t > mid) update(u << 1 | 1, mid + 1, r, s, t, x);
        maintain(u);
    }

    ll ask(int u, int l, int r, int s, int t) {
        if (s <= l && r <= t) return val[u];
        pushdown();
        int mid = l + r >> 1;
        if (t <= mid) return ask(u << 1, l, mid, s, t);
        if (s > mid) return ask(u << 1 | 1, mid + 1, r, s, t);
        return ask(u << 1, l, mid, s, t) + ask(u << 1 | 1, mid + 1, r, s, t);
    }
} sg;

int n;
int a[maxn];
vector<int> adj[maxn];
int fa[maxn], dep[maxn], siz[maxn], son[maxn];

void init(int u, int p) {
    fa[u] = p, dep[u] = dep[p] + 1, siz[u] = 1;
    for (auto v : adj[u]) {
        if (v == p) continue;
        init(v, u);
        siz[u] += siz[v];
        if (siz[v] > siz[son[u]]) son[u] = v;
    }
}
int clk;
int dfn[maxn], top[maxn];

void dfs(int u, int t) { //  当前节点，重链顶节点
    dfn[u] = ++clk, top[u] = t;
    sg.update(1, 1, n, dfn[u], dfn[u], a[u]); // build seg
    if (son[u]) dfs(son[u], t);
    for (auto v : adj[u]) {
        if (v == fa[u] || v == son[u]) continue;
        dfs(v, v);
    }
}

ll ask(int u, int v) {
    ll ret = 0;
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u, v); // keep u deeper
        ret += sg.ask(1, 1, n, dfn[top[u]], dfn[u]);
        u = fa[top[u]];
    }
    if (dep[u] < dep[v]) swap(u, v);
    ret += sg.ask(1, 1, n, dfn[v], dfn[u]);
    return ret;
}

int main() {
    int Q;
    cin >> n >> Q;
    rf(i, n) cin >> a[i];
    for (int i = 1; i <= n - 1; ++i) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    init(1, 0);
    dfs(1, 1);
    while (Q--) {
        int op;
        cin >> op;
        if (op == 1) {
            int pos, x;
            cin >> pos >> x;
            sg.update(1, 1, 1, dfn[pos], dfn[pos], x);
        } else if (op == 2) {
            int pos, x;
            cin >> pos >> x;
            sg.update(1, 1, 1, dfn[pos], dfn[pos] + siz[pos] - 1, x);
        } else if (op == 3) {
            int x;
            cin >> x;
            printf("%d\n", ask(dfn[1], dfn[x]));
        }
    }
    // rf(i, n) printf("%d ", top[i]);
    // puts("");
}

/*
5
1 2
1 3
3 4
3 5
5
2 1
4 2
4 5
3 2
1 5

*/